package com.dkd.manage.service.impl;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.util.StrUtil;
import com.dkd.common.constant.DkdContants;
import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.DateUtils;
import com.dkd.common.utils.bean.BeanUtils;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.TaskDetails;
import com.dkd.manage.domain.VendingMachine;
import com.dkd.manage.domain.dto.TaskDetailsDto;
import com.dkd.manage.domain.dto.TaskDto;
import com.dkd.manage.domain.vo.TaskVo;
import com.dkd.manage.service.IEmpService;
import com.dkd.manage.service.ITaskDetailsService;
import com.dkd.manage.service.IVendingMachineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.dkd.manage.mapper.TaskMapper;
import com.dkd.manage.domain.Task;
import com.dkd.manage.service.ITaskService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工单Service业务层处理
 * 
 * @author muchun
 * @date 2025-07-28
 */
@Service
public class TaskServiceImpl implements ITaskService 
{
    @Autowired
    private TaskMapper taskMapper;

    /**
     * 查询工单
     * 
     * @param taskId 工单主键
     * @return 工单
     */
    @Override
    public Task selectTaskByTaskId(Long taskId)
    {
        return taskMapper.selectTaskByTaskId(taskId);
    }

    /**
     * 查询工单列表
     * 
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<Task> selectTaskList(Task task)
    {
        return taskMapper.selectTaskList(task);
    }

    /**
     * 新增工单
     * 
     * @param task 工单
     * @return 结果
     */
    @Override
    public int insertTask(Task task)
    {
        task.setCreateTime(DateUtils.getNowDate());
        return taskMapper.insertTask(task);
    }

    /**
     * 修改工单
     * 
     * @param task 工单
     * @return 结果
     */
    @Override
    public int updateTask(Task task)
    {
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }

    /**
     * 批量删除工单
     * 
     * @param taskIds 需要删除的工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskIds(Long[] taskIds)
    {
        return taskMapper.deleteTaskByTaskIds(taskIds);
    }

    /**
     * 删除工单信息
     * 
     * @param taskId 工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskId(Long taskId)
    {
        return taskMapper.deleteTaskByTaskId(taskId);
    }

    /**
     * 根据工单查询工单虚拟对象列表，包括工单类型
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    public List<TaskVo> selectTaskVoList(Task task) {
        return taskMapper.selectTaskVoList(task);
    }

    //设备service
    @Autowired
    IVendingMachineService vendingMachineService;

    //员工service
    @Autowired
    IEmpService empService;
    @Autowired
    ITaskDetailsService taskDetailsService;
    /**
     * 新增运维，运营工单
     * @param taskDto
     * @return 结果:影响数据行数
     */
    @Transactional
    @Override
    public int insertTaskDto(TaskDto taskDto) {
        //1-查询设备是否存在
        VendingMachine vm = vendingMachineService.selectVendingMachineByInnerCode(taskDto.getInnerCode());
        if(vm == null){
            throw new ServiceException("设备不存在");
        }


        //2.校验售货机状态与工单类型是否相符
        checkVMStatusFixTask(vm.getVmStatus(),taskDto.getProductTypeId());
        //3.检查设备是否有未完成的工单
        //创建task对象，设置设备编号和工单类型，以及工单状态为进行中
        Task taskParam = new Task();
        taskParam.setInnerCode(taskDto.getInnerCode());
        taskParam.setProductTypeId(taskDto.getProductTypeId());
        taskParam.setTaskStatus(DkdContants.TASK_STATUS_PROGRESS);

        //调用taskMapper.selectTaskByTaskParam(taskParam)查询是否有未完成的工单
        hasTask(taskParam);

        //4.判断员工是否存在
        Emp emp = empService.selectEmpById(taskDto.getUserId());
        if(emp == null){
            throw new ServiceException("员工不存在");
        }
        //5.检查员工区域是否与设备区域一致
        if(!emp.getRegionId().equals(vm.getRegionId())){
            throw new ServiceException("员工区域与设备区域不一致，不能创建工单");
        }
        //6.将dto对象转换为po对象，并补充属性，保存到数据库
        Task task = new Task();
        BeanUtils.copyProperties(taskDto, task);//复制属性
        task.setTaskStatus(DkdContants.TASK_STATUS_CREATE);
        task.setUserId(emp.getId());
        task.setUserName(emp.getUserName());
        task.setRegionId(emp.getRegionId());
        task.setAddr(vm.getAddr());
        task.setCreateTime(DateUtils.getNowDate());
        task.setUpdateTime(DateUtils.getNowDate());
        task.setTaskCode(generateTaskNo());//生成工单号
        int insertTask = taskMapper.insertTask(task);
        //7.判断是否是补货工单，
        if(taskDto.getProductTypeId() == DkdContants.TASK_TYPE_SUPPLY){
            //8.如果是补货工单，保存工单详情
            List<TaskDetailsDto> details = taskDto.getDetails();
            //判断details是否为空
            if(details == null || details.size() == 0){
                throw new ServiceException("补货工单详情不能为空");
            }
            //将Dto转换为Po补充属性
            List<TaskDetails> detailsList = details.stream().map(dto -> {
                TaskDetails detailsPo = new TaskDetails();
                BeanUtils.copyProperties(dto, detailsPo);
                detailsPo.setTaskId(task.getTaskId());
                return detailsPo;
            }).collect(Collectors.toList());
            //保存到数据库
            int insertTaskDetails = taskDetailsService.batchInsertTaskDetails(detailsList);
            if(insertTaskDetails!= detailsList.size()){
                throw new ServiceException("保存工单详情失败");
            }

        }

        return insertTask;
    }

    /**
     * 取消工单
     * @param task
     * @return 结果:影响数据行数
     */
    @Override
    public int cancelTask(Task task) {
        //1,判断工单状态是否已经取消，先从数据库获取taskId的工单数据
        Task taskFromDb = taskMapper.selectTaskByTaskId(task.getTaskId());
        if(taskFromDb == null){
            throw new ServiceException("工单不存在");
        }
        //2,判断工单状态是否已经取消
        if(taskFromDb.getTaskStatus() == DkdContants.TASK_STATUS_CANCEL){
            throw new ServiceException("工单已经取消，不需要再次取消");
        }
        //3,判断工单是否已经完成，如果已经完成，则不能取消
        if(taskFromDb.getTaskStatus() == DkdContants.TASK_STATUS_FINISH){
            throw new ServiceException("工单已经完成，不能取消");
        }

        return taskMapper.cancelTask(task);
    }

    //注入redisTemplate
    @Autowired
    private RedisTemplate redisTemplate;

    //生成流水号
    //生成工单号（当天日期+流水号）
    private String generateTaskNo() {
        //获取当前日期并格式为yyyyMMdd
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String dateStr = dateFormat.format(DateUtils.getNowDate());
        //从redis中获取流水号
        String key = "dkd:task:no:" + dateStr;
        //如果redis中没有key,则设置初始值1，并设置过期时间为1天
        if(!redisTemplate.hasKey(key)){
//            redisTemplate.opsForValue().set(key, "1");
//            redisTemplate.expire(key, 1, TimeUnit.DAYS);
            redisTemplate.opsForValue().set(key, 1, Duration.ofDays(1));
            return dateStr + "001";
        }
        //如果redis中有key,则获取当前值，自增1，格式为yyyyMMdd0002
        Long no = redisTemplate.opsForValue().increment(key);
        return dateStr + StrUtil.padPre(no.toString(), 4, '0');
    }

    //调用taskMapper.selectTaskByTaskParam(taskParam)查询是否有未完成的工单
    private void hasTask(Task taskParam) {
        List<Task> taskList = taskMapper.selectTaskList(taskParam);
        if(taskList!= null && taskList.size() > 0){
            throw new ServiceException("该设备有未完成的工单，请先完成后再创建新的工单");
        }
    }

    //2.校验售货机状态与工单类型是否相符
    void checkVMStatusFixTask(Long vmStatus,Long productTypeId) {
        //如果是投放工单，设备在运行中，抛出异常
        if(productTypeId == DkdContants.TASK_TYPE_DEPLOY && vmStatus == DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("该设备正在运行中，不能创建投放工单");
        }
        //如果是维修工单，设备不在运行中，抛出异常
        if(productTypeId == DkdContants.TASK_TYPE_REPAIR && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("该设备不在运行中，不能创建维修工单");
        }
        //如果是补货工单，设备不在运行中，抛出异常
        if(productTypeId == DkdContants.TASK_TYPE_SUPPLY && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("该设备不在运行中，不能创建补货工单");
        }
        //如果是撤机工单，设备不在运行中，抛出异常
        if(productTypeId == DkdContants.TASK_TYPE_REVOKE && vmStatus != DkdContants.VM_STATUS_RUNNING){
            throw new ServiceException("该设备不在运行中，不能创建撤机工单");
        }
    }
}
